package com.edushare.common.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import org.apache.cayenne.exp.Expression;
import org.apache.cayenne.query.SelectQuery;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.edushare.common.constants.ApplicationConstants;
import com.edushare.common.orm.ORMInterface;
import com.edushare.common.util.CryptionUtil;
import com.edushare.common.util.StringUtil;
import com.edushare.common.vo.CourseInstances;
import com.edushare.common.vo.Departments;
import com.edushare.common.vo.Enrolments;
import com.edushare.common.vo.Groups;
import com.edushare.common.vo.Universities;
import com.edushare.common.vo.UserDeptLink;
import com.edushare.common.vo.UserRoles;
import com.edushare.common.vo.Users;

public class UsersDAO extends CayenneBasedDAO {
	
	private static Log log = LogFactory.getLog(UsersDAO.class);

	public UsersDAO(ORMInterface ormInterface) {
		super(ormInterface);
	}
	
	public void commit(){
		getDataContext().commitChanges();
	}
	
	@SuppressWarnings("unchecked")
	public Users getUserFromUserName(String username){
		Users user = null;
		Expression exp = Expression.fromString("userName = $username");
		HashMap params = new HashMap();
		params.put("username", username);
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(params));
		List lst = getDataContext().performQuery(query);
		if(lst!=null && lst.size() > 0)
			user = (Users)lst.get(0);
		return user;
	}

	@SuppressWarnings("unchecked")
	public Users getAuthenticUser(String username, String pwd) {
		Users user = null;
		Expression exp = Expression.fromString("userName = $username and password = $pass");
		HashMap params = new HashMap();
		params.put("username", username);
		params.put("pass", DigestUtils.sha256Hex(pwd));
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(params));
		List lst = getDataContext().performQuery(query);
		if(lst!=null && lst.size() > 0)
			user = (Users)lst.get(0);
		return user;
	}

	/**
	 * Will be deleted on 0.2.0 release
	 * @deprecated
	 * @param hm
	 * @param univ
	 * @param deptRoleCode
	 * @param univRoleCode
	 * @param fromUser
	 * @param customMessage
	 */
	public void sendBulkInviteToDept(HashMap<Departments, String> hm,
										Universities univ, 
										int deptRoleCode,
										int univRoleCode,
										Users fromUser,
										String customMessage) 
	{
		Set<Departments> deps = hm.keySet();
		for(Departments dep: deps){
			String emailStr = hm.get(dep);
			String[] emails;
			if(StringUtil.isValid(emailStr))
			{
				emailStr = 
							emailStr.replace("  ", " ") //replace all many spaces to single
									.replace(" ", ";") // replace all single spaces to ;
									.replace(",", ";") // replace all , to ;
									.replace(";;", ";"); // replace all ;; to ;
				emails = emailStr.split(";");
			
			
				for(String individualEmail: emails){
					Users u = getDataContext().newObject(Users.class);
					u.setEmail(individualEmail);
					u.setCreationTimestamp(new Date(System.currentTimeMillis()));
					u.setConfKey(individualEmail);
					u.setStatus(Users.INVITED);
					u.setLandingPageId(Users.LANDING_PAGE_USER_INVITATION);
					u.setUserName(u.getConfKey());//set temp user-name!
					UserDeptLink userDeptLink = getDataContext().newObject(UserDeptLink.class);
					userDeptLink.setDepartmentLink(dep);
					userDeptLink.setUserLink(u);
					userDeptLink.setRoleType(deptRoleCode);
					getDataContext().commitChanges();
					
					UserRoles userUnivLink = getDataContext().newObject(UserRoles.class);
					userUnivLink.setUser(u);
					userUnivLink.setUniversity(univ);
					userUnivLink.setRoleType(univRoleCode);
					
					getDataContext().commitChanges();
					
					new EmailTemplatesDAO(ormInterface).sendJoinUniversityMailToTeachersWithKey(u, fromUser, univ, u.getConfKey(), customMessage);
					
				}
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public Users validateEmailInvite(String confKeyFromUrl){
		Users u = null;
		try {
			String decryptedKey = CryptionUtil.decrypt(confKeyFromUrl);
			Expression exp = Expression.fromString("confKey = $decKey");
			HashMap hm = new HashMap();
			hm.put("decKey", decryptedKey);
			SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(hm));
			List<Users> ul = getDataContext().performQuery(query);
			if(ul!=null && ul.size()>1)
				log.error("WARNING:: MORE THAN ONE RECORD EXISTS FOR CONFKEY BY INVITATION. CONF KEY IS: " +
						""+confKeyFromUrl);
			if(ul!=null && ul.size()>0)
				u = ul.get(0);
		} catch (Exception e) {
			log.fatal("Decryption ERROR. Code is: "+ confKeyFromUrl);
		} 
		return u;
	}
	
	@SuppressWarnings("unchecked")
	public Users getUserByPk(Integer pk){
		Users user = null;
		Expression exp = Expression.fromString("userId = $userId");
		HashMap params = new HashMap();
		params.put("userId", pk);
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(params));
		List lst = getDataContext().performQuery(query);
		if(lst!=null && lst.size() > 0)
			user = (Users)lst.get(0);
		return user;		
	}
	
	@SuppressWarnings("unchecked")
	public Users getUsersByEMail(String email){
		Users user = null;
		Expression exp = Expression.fromString("email = $email");
		HashMap<String,String> params = new HashMap<String,String>();
		params.put("email", email);
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(params));
		List<Users> lst = getDataContext().performQuery(query);
		if(lst!=null && lst.size() > 0)
			user = (Users)lst.get(0);
		return user;		
		
	}

	public UserRoles getNewUserRole(){
		UserRoles userRole = new UserRoles();
		getDataContext().registerNewObject(userRole);
		return userRole;
	}
	
	public Users getNewUser(){
		Users user = new Users();
		getDataContext().registerNewObject(user);
		return user;
	}
	
	public Users newUser(String email){
		Users user = new Users();
		user.setEmail(email);
		return inviteNewUser(user);
	}
	
	public Users inviteNewUser(Users u){
		u.setCreationTimestamp(new Date());
		u.setStatus(Users.INVITED);
		u.setConfKey(u.getEmail());
		u.setLandingPageId(Users.LANDING_PAGE_USER_INVITATION);
		u.setUserName(u.getConfKey());
		
		getDataContext().registerNewObject(u);
		getDataContext().commitChanges();
		return u;
	}

	public List<CourseInstances> getCourseInstances(Users user, int enrolmentRole) {
			List<Enrolments> enrolledCourses = user.getEnrolments();
			ArrayList<CourseInstances> cil = new ArrayList<CourseInstances>();
			for(Enrolments e: enrolledCourses){
				if(e.getEnrolmentType() == enrolmentRole)
					cil.add(e.getCourseInstance());
			}
			
			return cil;
	}

	public List<Users> getGroupMembers(Groups g) {
		return getGroupMembers(g,0);
	}
	
	public List<Users> getUnivMembers(Universities univ, int role){
		List<Users> userList = new ArrayList<Users>();
		List<UserRoles> rList = univ.getUserRoleList();
		for(UserRoles r:rList){
			if(r.getRoleType() == role){
				userList.add(r.getUser());
			}
		}
		return userList;
	}
	
	public List<Users> getUnivMembers(Universities univ){
		List<Users> userList = getUnivMembers(univ, UserRoles.ADMIN_ROLE);
		userList.addAll(getUnivMembers(univ, UserRoles.STUDENT_ROLE));
		userList.addAll(getUnivMembers(univ, UserRoles.TEACHER_ROLE));
		return userList;
	}

	@SuppressWarnings("unchecked")
	private List<Users> getGroupMembers(Groups g, int role) {
		Expression exp = Expression.fromString("groupMemberships.group = $grp and groupMemberships.role = $rl");
		HashMap<String, Object> hm = new HashMap<String, Object>();
		hm.put("grp", g);
		if(role!=0){
			hm.put("rl", role);
		}
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(hm, true));
		query.setPageSize(ApplicationConstants.PAGE_SIZE);
		return getDataContext().performQuery(query);
	}

	@SuppressWarnings("unchecked")
	public Users getUserByUserNameOrEmail(String emailorid) {
		Expression exp = Expression.fromString("userName = $un or email = $em");
		HashMap<String, String> hm = new HashMap<String, String>();
		hm.put("un", emailorid);
		hm.put("em", emailorid);
		SelectQuery query = new SelectQuery(Users.class, exp.expWithParameters(hm, true));
		List<Users> ul = getDataContext().performQuery(query);
		if(ul!=null && ul.size() > 0){
			return ul.get(0);
		}
		return null;
	}
	
	@SuppressWarnings("unchecked")
	public List<Users> getAllUsers(){
		SelectQuery query = new SelectQuery(Users.class);
		return getDataContext().performQuery(query);
	}
	
	public Users updateUserDetails(Users u, String firstName, String lastName){
		if(u == null)
			return u;
		if(StringUtil.isValid(firstName))
			u.setFirstName(firstName);
		if(StringUtil.isValid(lastName))
			u.setLastName(lastName);
		commit();
		return u;
}
}
